package brwarner.game 
{
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	import brwarner.GridEvent;
	import flash.text.engine.ElementFormat;
	/**
	 * ...
	 * @author Brook Jensen
	 */
	public class GridSquare extends EventDispatcher
	{
		//Tile types
		public static const PLAIN:Number = 0;
		public static const DESERT:Number = 1;
		public static const ICE:Number = 2;
		public static const RIVER:Number = 3;
		public static const FOREST:Number = 4;
		public static const MOUNTAIN:Number = 5;
		public static const SNOW_MOUNTAIN:Number = 6;
		public static const RANDOM_MAX:Number = 7;
		public static const TOWER:Number = 8;
		
		//Human types
		public static const HUMAN_FREE:Number = 0;
		public static const HUMAN_CITY:Number = 1;
		public static const HUMAN_BASE:Number = 2;
		
		//Sprite type
		private var _spriteID:Number;
		
		//Population of humans living in the square
		private var _population:Number = 0;
		
		//Infection level
		private var _infection:Number;
		
		//Our position
		private var _pos:Point;
		
		//Parent game grid
		private var _grid:GameGrid;
		
		//Gets our position
		public function get Tile( ) : Point
		{
			return _pos;
		}
		
		//Helper function which checks if ONLY the supplied directions are the same type as us
		private function checkTypes( directions:Array/*, not:Array*/ ):Boolean
		{			
			//Check that both pass their corresponding tests
			return directions.every( function( e:Number, i:Number, a:Array ) {
				var p:Point = Tile.add( Direction.directionVector(e) );
				return _grid.inBounds(p) && (_grid.getTile(p).Type == Type);
			}, this ) 
				/*&& 
				not.every( function( e:Number, i:Number, a:Array ) {
				var p:Point = Tile.add( Direction.directionVector(e) );
				return !_grid.inBounds(p) || !(_grid.getTile(p).Type == Type);
			}, this)*/;
		}
		
		private function calcSpriteType( ):Number
		{
			//Basic city checks
			if ( _infection > 0 )
			{
				if ( _infection == HUMAN_BASE ) 
				{
					return 4;
				}
				else {
					if ( Type == TOWER ) {
						return 11;
					}
					switch( Level ) {
						case 0: return 9;
						case 1: return 10;
						case 2: return 3;
					}
				}
			}
			switch( Type )
			{
				case PLAIN:
				case DESERT:
				case ICE:
					return Type;
					break;
				case RIVER:
				{
					//Conditions
					if ( checkTypes( [ 0, 2, 4, 6 ] ) ) return 19; //Middle
					if ( checkTypes( [ 2, 3, 4, 5, 6 ] ) ) return 13; //Top-Middle
					if ( checkTypes( [ 0, 1, 2, 6, 7 ] ) ) return 25; //Bottom-middle
					if ( checkTypes( [ 0, 1, 2, 3, 4 ] ) ) return 18; //Left
					if ( checkTypes( [ 0, 4, 5, 6, 7 ] ) ) return 20; //Right
					if ( checkTypes( [ 2, 3, 4 ] ) ) return 12; //Top-Left
					if ( checkTypes( [ 6, 5, 4 ] ) ) return 14; //Top-Right
					if ( checkTypes( [ 0, 1, 2 ] ) ) return 24; //Bottom-left
					if ( checkTypes( [ 0, 6, 7] ) ) return 26; //Bottom-right
					if ( checkTypes( [ 2, 4 ] ) ) return 30; //River up-right
					if ( checkTypes( [ 0, 2 ] ) ) return 37; //River down-right
					if ( checkTypes( [ 0, 6 ] ) ) return 38; //River right-up
					if ( checkTypes( [ 4, 6 ] ) ) return 32; //River right-down
					if ( checkTypes( [ 2, 6 ] ) || checkTypes( [ 2 ] ) || checkTypes( [ 6 ] ) ) return 31; //River horizontal
					if ( checkTypes( [ 0, 4 ] ) || checkTypes( [ 0 ] ) || checkTypes( [ 4 ] ) ) return 36; //River vertical
					return 16; //Single
				} break;
				case FOREST:
				{
					return 6;
				} break;
				case MOUNTAIN:
				{
					return 7;
				} break;
				case SNOW_MOUNTAIN:
				{
					return 8;
				}break;
				case TOWER:
				{
					return 5;
				}break;
			}
			return -1;
		}
		
		//Type of tile
		var _type:Number;
		
		//Real type
		var _realType:Number;
		var _typeEffectTime:Number = 0;
		
		public function GridSquare( grid:GameGrid, type:Number, x:Number, y:Number ) 
		{
			//Store the type of tile
			_realType = _type = type;
			_infection = HUMAN_FREE;
			
			//Store grid
			_grid = grid;
			
			//Store the position
			_pos = new Point( x, y );
			
			_population = 0;
		}
		
		public function refreshSprite( ):void
		{
			_spriteID = calcSpriteType();
			_grid.dispatchEvent( new GridEvent( GridEvent.GRID_STATUS_CHANGED, _pos.x, _pos.y ) );
		}
		
		public function get Type( ):Number
		{
			return _type;
		}
		public function set Type( t:Number ) :void
		{
			_realType = _type = t;
			_typeEffectTime = 0;
			_grid.refreshSprites();
			_grid.dispatchEvent( new GridEvent( GridEvent.GRID_STATUS_CHANGED, _pos.x, _pos.y ) );
		}
		public function get Population( ) :Number
		{
			return _population;
		}
		public function set Population( p:Number ):void
		{
			if ( p.toString() == "NaN" ) return;
			if ( p > GameConstants.POPULATION_MAX ) p = GameConstants.POPULATION_MAX;
			_population = p;
		}
		
		public function tempTypeChange( newType:Number, frames:Number ) {
			_type = newType;
			_typeEffectTime = frames;
			_grid.refreshSprites();
			_grid.dispatchEvent( new GridEvent( GridEvent.GRID_STATUS_CHANGED, _pos.x, _pos.y ) );
		}
		
		public function update( ):void {
			if ( _typeEffectTime > 0 ) {
				_typeEffectTime--;
				if ( _typeEffectTime == 0 ) {
					Type = _realType;
				}
			}
		}
		
		public function Die( ):void
		{
			//Destroy any cities on this land
			_infection = 0;
			_population = 0;
			Type = DESERT;
		}
		
		public function Damage( p:Number ):void
		{
			if ( Infected )
			{
				//Decrease population
				_population -= p;
				if ( _population <= 0 ) {
					_population = 0;
					Die();
				}
			}
		}
		
		//Gets the city level
		public function get Level( ):Number {
			if ( !Infected ) return -1;
			if ( Infection == HUMAN_BASE ) return -1;
			for ( var i = GameConstants.POPULATION_LEVELS.length-1; i >= 0 ; i-- ) {
				if ( Population >= GameConstants.POPULATION_LEVELS[i] ) return i;
			}
			return -1;
		}
		
		public function get Infected( ):Boolean { return _infection > 0; }
		public function set Infection( i:Number ) {
			_infection = i;
			_population = GameConstants.INITIAL_POP;
			refreshSprite();
			_grid.dispatchEvent( new GridEvent( GridEvent.GRID_STATUS_CHANGED, _pos.x, _pos.y ) );
		}
		public function get Infection( ):Number { return _infection; }
		
		//Gets the sprite type
		public function get SpriteType( ):Number { return _spriteID; }
		
		
	}

}